package net.qiqb.core.executing;

import cn.hutool.core.util.ReflectUtil;
import net.qiqb.core.domain.annotation.BaseEntity;
import net.qiqb.core.domain.event.DomainEvent;
import net.qiqb.core.domain.event.DomainEventContext;

import java.util.*;

public class ExecutingContext {

    public static final String DELETE_AGGREGATE_ROOT_OBJ = "_delete_aggregate_root_obj";

    public static final String NEW_AGGREGATE_ROOT_OBJ = "_new_aggregate_root_obj";


    private final ExecutingContext parent;

    private final DomainEventContext domainEventContext = new DomainEventContext();

    private final Set<Object> newEntityIds = new HashSet<>();


    /**
     * 命令执行过程中添加的数据需要传递。
     */
    private final Map<String, Object> attributes = new HashMap<>();

    private final List<ExceptionCallback> exceptionCallbacks = new ArrayList<>();


    /////////////属性////////////
    public ExecutingContext(ExecutingContext parent) {
        this.parent = parent;
    }

    public ExecutingContext() {
        this(null);
    }

    public void addNewEntityId(Object id) {
        this.newEntityIds.add(id);
    }

    public boolean isNewEntityId(Object id) {
        return this.newEntityIds.contains(id);
    }

    public boolean isNewEntity(Object aggregateRoot) {
        return this.newEntityIds.contains(getId(aggregateRoot));
    }

    protected static Object getId(Object aggregateRoot) {
        // 获取领域对象的id
        final Object id = lookupAggregateRootId(aggregateRoot);
        if (id != null) {
            return id;
        }
        throw new IllegalStateException("找不到聚合根ID");
    }

    private static Object lookupAggregateRootId(Object aggregateRootObj) {
        if (aggregateRootObj instanceof BaseEntity<?>) {
            return ((BaseEntity<?>) aggregateRootObj).getId();
        }
        // 默认找id 属性
        final Object idValue = ReflectUtil.getFieldValue(aggregateRootObj, "id");
        if (idValue != null) {
            return idValue;
        }
        throw new RuntimeException("找不到聚合根id");
    }

    public void addAttribute(String name, Object value) {
        this.attributes.put(name, value);
    }

    public void removeAttribute(String name) {
        this.attributes.remove(name);
    }

    public Object getAttribute(String name) {
        return this.attributes.get(name);
    }


    /**
     * 当异常出现时进行回调
     * <ul>
     *     <li>执行业务过程中，如果有某些行为需要监控（支付接口），在后续程序运行报错的时候，需要回滚（退钱接口）。</li>
     * </ul>
     *
     * @param callback 当运行时出现异常时，需要执行当回调函数
     */
    public void listenException(ExceptionCallback callback) {
        this.exceptionCallbacks.add(callback);
    }


    public List<ExceptionCallback> listExceptionCallbacks() {
        return this.exceptionCallbacks;
    }

    /**
     * 添加领域事件
     *
     * @param event 领域事件
     */
    public void addEvent(Object event) {
        this.domainEventContext.add(event);
    }

    /**
     * 删除领域事件
     *
     * @param event 领域事件
     */
    public void removeEvent(Object event) {
        this.domainEventContext.remove(event);
    }

    /**
     * 获取所有命令执行过程中的领域事件
     *
     * @return
     */
    public List<DomainEvent> listEvents() {
        return this.domainEventContext.getEvents();
    }

    public ExecutingContext getParent() {
        return parent;
    }
}
